test(cov): coverage drivers for never-measured surfaces (+ the 85% branch ceiling, measured) - #147
Merged
Conversation
Four new C drivers plus six runner scripts aimed at the two largest recoverable slices of the coverage gap documented in test/coverage/FULL-COVERAGE-REPORT-3.md: the 515 never-called functions, and the OOM error-return branches. New drivers (test/c/cov_*.c, all single-process, SIGALRM-guarded): * cov_api_surface.c (418 checks) -- the DB_ENV / DB / DBC / DB_TXN / DB_MPOOLFILE getter + callback-setter surface and the argument-validation / ENV_ILLEGAL_AFTER_OPEN halves of the setters. Targets the ~60 never-called getters in db_method.c (24), env_method.c (21), mp_fmethod.c (8) and db_cds.c (8): the Tcl bindings expose the setters a workload needs and never read a knob back, so every getter measured cold. * cov_rep_api.c (254 checks) -- the replication + repmgr configuration and query surface: rep_get_config/limit/nsites/priority/request/ timeout/clockskew, rep_set_clockskew/request/nsites, txn_applied, the DB_SITE handle methods, repmgr_get_ack_policy/config/local_site/ site_by_eid, the channel *_inval stubs, and the base-API-vs-repmgr cross-rejection branches no Tcl rep test reaches (each picks one API and stays). * cov_logrec_print.c (5115 checks) -- generates a log holding 41 DISTINCT record kinds (hash contract/metagroup, queue extent create+delete, page truncation, compaction realloc, heap ops, off-page dups, cursor adjust under a child txn, subdb create, transactional rename/remove, DIAGNOSTIC, a prepared txn), then walks it through BOTH per-record dispatch tables: db_printlog (the ~39 *_autop.c printers) and db_log_verify (62 of log_verify_int.c's 99 functions -- the largest never-called count in the tree). One workload, two cold surfaces. * cov_oom_paths.c -- a COVERAGE-oriented OOM sweep. fi_sweep.c is the bug-finding sweep and its children _exit(), which skips gcov's atexit flush, so its 947 failure points contribute ZERO measured coverage. This sweeps the same __os_* seam with a breadth-first workload and calls __gcov_dump() in each child before _exit. 6,016 of report #3's 38,998 missing branches sit on `if ((ret = f()) != 0)` lines. Requires --enable-faultinject; SKIPs cleanly without it. New runners for tiers that already existed and passed but that no coverage driver had ever run, so what they cover always measured cold: * run_cov_cutest.sh -- the 12-suite CuTest binary, one suite per process. TestChannel brings up three live repmgr sites and drives the whole DB_CHANNEL API, which is exactly repmgr_method.c's never-called set. * run_cov_fuzz_corpus.sh -- the committed corpus + crash seeds replayed through FUZZ_STANDALONE harnesses against THIS build (run.sh and check-crashes.sh build their own ASan libdb, so the corrupt-input rejection branches were never counted). * run_cov_dst.sh -- the 41 DST scenarios; SKIPs when the library lacks --enable-dst. test/coverage/full_run4.sh is a portable rework of full_run3_combined.sh: repo root derived from the script location, tcl/gcov/lcov from the environment, PHASE 1 throttled to $COV_PAR so the run survives an 8-way box, --enable-dst + --enable-faultinject added (both additive and inert until armed), and PHASE 2 folds in recd_handlers (which report #3 recorded as a measurement gap) plus all the tiers above. SKIP_PHASE1/SKIP_PHASE2/PHASE2_ONLY_NEW allow adding to an existing .gcda accumulation, which is how per-batch deltas are measured. Measurement only -- no engine source touched. Five engine/harness findings surfaced while validating these drivers and are written up in the report, not fixed here.
The driver did not compile: it called __db_compress_int/__db_decompress_int/
__db_decompress_int32 with a trailing length out-parameter, but all three RETURN
the byte count instead (see bt_compress.c: 'ptr += __db_compress_int(ptr, v)').
Fixed the three call sites.
It then ran with 12 failures, all of which were the driver asserting contracts
the code never promised -- verified against the source rather than filed as bugs:
- 8 x 'encoding is not order-preserving' at the size-class boundaries. The
compressed-int encoding is deliberately NOT order-preserving, and does not
need to be: its only in-tree users are bt_compress.c's prefix/suffix lengths
and data sizes, which are decoded numerically and never compared as encoded
byte strings. Assertion removed, with a comment recording why.
- 4 x '__db_getlong("0x10") rejected, expected accept'. __db_getlong and
__db_getulong call strtol/strtoul with base 10 explicitly, so rejecting hex is
correct. Cases now expect rejection; noted that "010" is decimal ten.
cov_codecs: 290326 checks, 0 failures.
|
ABI diff produced no report (build skipped or no base tag). Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md. |
Coccinelle convention checksNo new violations. ✅ Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in. |
This was referenced Sep 7, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase C of the evolved plan. Adds test drivers for surfaces the suite never measured, and — importantly — establishes with arithmetic that >85% branch is not a reachable target, while >85% function is.
The honest headline: 85% branch is out of reach; 85% function is not
Current (committed lcov, report #3): line 68.0%, branch 50.2% (39238/78236), function 80.5% (2129/2644).
Reaching 85% branch needs +27,262 branches = 70% of every currently-missing branch. The structural reason: ~1,662
if ((ret = f()) != 0)sites insrc/are OOM/error-return legs reachable only by malloc-fault injection, andfi_sweep.creaches exactly one failure point per process run (it sweeps K=1..M) — so covering K error legs costs K runs. Another 2,368 are NULL checks and 1,496 flag tests.>85% function is the reachable goal: it needs only +118 functions, and ~250 recoverable ones were identified.
Drivers added (each validated with real check counts)
cov_api_surface.cdb_method.c24,env_method.c21,mp_fmethod.c8,db_cds.c8)cov_rep_api.cDB_SITE,txn_applied, base-API↔repmgr cross-rejectioncov_logrec_print.c*_autop.cprinters, 62 oflog_verify_int.c's 99 functionscov_codecs.cdb_compint.c's 66 missing branches,db_getlong/getulongcov_oom_paths.c__gcov_dump()before_exitcutest8/9 suites, fuzz 3 harnesses/14 inputs, DST skips cleanlyTwo measurement gaps found (why some tiers showed as 0%)
fi_sweep.c's 947 fault points measured as zero because the child_exit()s without__gcov_dump(). Any driver that_exit()s must dump first or its coverage is invisible.test/fuzz/run.shbuilds its own ASan libdb, so corrupt-input rejection branches never reach the main profile.Five latent defects found (reported, not fixed here)
__lock_set_lk_priority/get_lk_priority(lock_method.c:482,507) —__lock_getlocker(create=0)returns 0 with*retp=NULL, both deref unconditionally;__lock_vec_pp(lock.c:93) shares the pattern.rep_get_nsiteson an unopened repmgr handle (12-line repro;ENV_NOT_CONFIGUREDis a no-op pre-open).__cdsgroup_begininstalls 8 ofDB_TXN's 12 methods —get_priority/set_priority/set_commit_token/set_txn_lsnpare NULL; calling them jumps to 0x0.TestQueue.c:64buffer overrun insh_l_as_string(harness bug, crashes at-O2).db_printlogin this fork has no-aflag (report 6.0.19 is missing #3's driver assumed it did).Honest limitation
No new measured before/after numbers. A full coverage run needs a big box (report #3 used a 96-way instance); on this 8-core box shared with concurrent agents (load 143–216) the BEFORE run did not finish.
baseline.txtis therefore untouched and report #4 is unwritten — the drivers are validated by their own check counts, not yet by a coverage delta. Finishing that is mechanical:full_run4.shaccumulates.gcdaso the AFTER run reuses the BEFORE work.Two driver assertions were corrected rather than filed as bugs: the compressed-int encoding is deliberately not order-preserving (only used for lengths/sizes, never as a sort key), and
__db_getlonguses base-10strtol, so rejecting"0x10"is correct.